package de.tuberlin.dima.minidb.parser;


import java.util.Arrays;
import java.util.Iterator;


/**
 * A parse tree node that represents a result column.
 * 
 * @author Stephan Ewen (sewen@cs.tu-berlin.de)
 */
public class OutputColumn implements ParseTreeNode
{
	
	/**
	 * The types of aggregation that are possible for that output column.
	 */
	public enum AggregationType
	{
		NONE, COUNT, SUM, AVG, MIN, MAX;
	}
	
	
	/**
	 * The name of the result column referenced by this node.
	 */
	protected final String name;
	
	/**
	 * The column that is produced.
	 */
	protected final Column column;
	
	/**
	 * The type of aggregation that is performed on this column.
	 */
	protected final AggregationType aggType;
	
	
	/**
	 * Create an result column with a given name for the given column.
	 * 
	 * @param col  The column that is produced.
	 * @param name The name of the result column.
	 */
	public OutputColumn(Column col, String name)
	{
		this(col, name, AggregationType.NONE);
	}
	
	/**
	 * Create an result column with a given name for the given column.
	 * 
	 * @param col  The column that is produced.
	 * @param name The name of the result column.
	 * @param agg The aggregation applied on this column.
	 */
	public OutputColumn(Column col, String name, AggregationType agg)
	{
		this.column = col;
		this.name = name;
		this.aggType = agg;
	}
	
	
	/**
	 * Gets the name of the result column that is referenced.
	 * 
	 * @return The result column name.
	 */
	public String getResultColumnName()
	{
		return name;
	}
	
	/**
	 * Gets the type of aggregation performed by this output column.
	 * 
	 * @return The aggregation type.
	 */
	public AggregationType getAggType()
	{
		return aggType;
	}

	/**
	 * Gets the column that is produced here.
	 * 
	 * @return The produced column.
	 */
	public Column getColumn()
	{
		return column;
	}

	/* (non-Javadoc)
	 * @see de.tuberlin.dima.minidb.parser.ParseTreeNode#getChildren()
	 */
	public Iterator<ParseTreeNode> getChildren()
	{
		return Arrays.asList(new ParseTreeNode[] {column}).iterator();
	}

	/* (non-Javadoc)
	 * @see de.tuberlin.dima.minidb.parser.ParseTreeNode#getNodeContents()
	 */
	public String getNodeContents()
	{
		if (column == null) {
			return name;
		}
		else {
			return aggType == AggregationType.NONE ?
					column.getTableAlias() + "." + column.getColumnName() + " AS " + name :
					aggType.name() + "(" + column.tableAlias + "." +
					column.getColumnName() + ") AS " + name;
		}
	}

	/* (non-Javadoc)
	 * @see de.tuberlin.dima.minidb.parser.ParseTreeNode#getNodeName()
	 */
	public String getNodeName()
	{
		return "Output Column";
	}
	
	/* (non-Javadoc)
	 * @see de.tuberlin.dima.minidb.parser.ParseTreeNode#getNumberOfChildren()
	 */
	public int getNumberOfChildren()
	{
		return 1;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	public String toString()
	{
		return getNodeContents();
	}
	
	/* (non-Javadoc)
	 * @see de.tuberlin.dima.minidb.parser.ParseTreeNode#isIdenticalTo(de.tuberlin.dima.minidb.parser.ParseTreeNode)
	 */
	public boolean isIdenticalTo(ParseTreeNode node)
	{
		if (node != null && node instanceof OutputColumn)
		{
			OutputColumn other = (OutputColumn) node;
			
			return ( (name == null && other.name == null) ||
					 (name != null && other.name != null &&
					  name.equalsIgnoreCase(other.name))
				   ) && (
					 (column == null && other.column == null) ||
					 (column != null && other.column != null &&
					  column.isIdenticalTo(other.column))
				   ) && (aggType == other.aggType);
		}
		
		return false;
		
	}

}
